using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using GraphAlgsPresentation.Core;
using GraphAlgsPresentation.ScriptBuilder;

namespace BFS
{
    class Program
    {
        private static Queue<int> queue = new Queue<int>();

        static void Main(string[] args)
        {
            double[,] a = ScriptBuilder.GetGraph(args[0]);
            int n = Convert.ToInt32(Math.Sqrt(a.Length));
            PrintAlgorithm();
            bool[] Free = new bool[n];            
            for (int i = 0; i < n; i++)
            {
                Free[i] = true;
                ScriptBuilder.HighlightLine(2);
                ScriptBuilder.Change_VertexLabel(i, "Free");
            }
            ScriptBuilder.HighlightLine(3);
            UpdateQueue();
            ScriptBuilder.EndStep();
            while (true)
            {
                ScriptBuilder.SetText(19, "");
                ScriptBuilder.SetText(20, "");
                ScriptBuilder.SetText(21, "");
                ScriptBuilder.ResetLine(2);
                ScriptBuilder.ResetLine(3);
                ScriptBuilder.HighlightLine(6);
                ScriptBuilder.EndStep();
                bool Found = false;
                int i;
                for (i = 0; i < n; i++)
                {
                    if (Free[i])
                    {
                        Found = true;
                        ScriptBuilder.Change_VertexFillColor(i, Color.Orange, DrawEffect.Blind);
                        ScriptBuilder.SetText(19, "I = " + (i + 1));
                        ScriptBuilder.ChangeTextFont(19, new Font("Times New Roman", 12,
                            FontStyle.Bold));
                        ScriptBuilder.EndStep();
                        break;
                    }
                }
                ScriptBuilder.ResetLine(6);
                ScriptBuilder.HighlightLine(7);
                ScriptBuilder.EndStep();
                if (!Found)
                {
                    ScriptBuilder.ResetLine(7);
                    ScriptBuilder.HighlightLine(8);
                    ScriptBuilder.SetText(18, "Finish!");
                    ScriptBuilder.EndStep();
                    break;
                }
                ScriptBuilder.ResetLine(7);
                ScriptBuilder.HighlightLine(9);
                ScriptBuilder.HighlightLine(10);
                ScriptBuilder.Change_VertexLabel(i, "");
                queue.Enqueue(i);
                Free[i] = false;
                UpdateQueue();
                ScriptBuilder.EndStep();                
                ScriptBuilder.ResetLine(9);
                ScriptBuilder.ResetLine(10);
                while (queue.Count > 0)
                {
                    int Current = queue.Dequeue();
                    ScriptBuilder.SetText(21, "");
                    ScriptBuilder.SetText(20, "Current = " + (Current + 1));
                    ScriptBuilder.ChangeTextFont(20, new Font("Times New Roman", 12,
                        FontStyle.Bold));
                    UpdateQueue();
                    ScriptBuilder.HighlightLine(12);
                    ScriptBuilder.Change_VertexFillColor(Current, Color.Red, DrawEffect.Blind);
                    ScriptBuilder.EndStep();
                    ScriptBuilder.ResetLine(12);
                    for (int j = 0; j < n; j++)
                    {
                        if (Free[j] && !double.IsNaN(a[Current, j]))
                        {
                            ScriptBuilder.HighlightLine(13);
                            ScriptBuilder.Change_EdgeLineColor(Current, j, Color.Red, DrawEffect.Blind);
                            ScriptBuilder.Change_VertexFillColor(j, Color.Blue, DrawEffect.Blind);
                            ScriptBuilder.SetText(21, "J = " + (j + 1));
                            ScriptBuilder.ChangeTextFont(21, new Font("Times New Roman", 12,
                                FontStyle.Bold));
                            ScriptBuilder.EndStep();
                            queue.Enqueue(j);
                            UpdateQueue();
                            Free[j] = false;
                            ScriptBuilder.ResetLine(13);
                            ScriptBuilder.HighlightLine(14);
                            ScriptBuilder.HighlightLine(15);
                            ScriptBuilder.Change_VertexLabel(j, "");
                            ScriptBuilder.EndStep();
                            ScriptBuilder.Change_VertexFillColor(j, Color.CadetBlue);
                            ScriptBuilder.ResetLine(14);
                            ScriptBuilder.ResetLine(15);
                        }
                    }
                    ScriptBuilder.Change_VertexFillColor(Current, Color.MediumOrchid);
                }
            }
            ScriptBuilder.Finish(args[1]);
        }

        private static void UpdateQueue()
        {
            int[] v = queue.ToArray();
            string text = "Queue = {";
            for (int i = 0; i < v.Length; i++)
            {
                text += " " + (v[i] + 1);
                if (i < v.Length - 1) text += ",";
            }
            text += " }";
            ScriptBuilder.SetText(18, text);
            ScriptBuilder.ChangeTextFont(18, new Font("Times New Roman", 12,
                FontStyle.Bold));
        }

        private static void PrintAlgorithm()
        {
            ScriptBuilder.InsertText("Thuật toán Breadth-First Search:");
            ScriptBuilder.ChangeTextFont(0, new Font("Times New Roman", 12,
                FontStyle.Bold | FontStyle.Italic));
            ScriptBuilder.InsertText("");
            ScriptBuilder.InsertText("Free[i] = True (all i)");
            ScriptBuilder.InsertText("Queue = Empty");
            ScriptBuilder.InsertText("");
            ScriptBuilder.InsertText("While (True)");
            ScriptBuilder.InsertText("\tFind i (Free[i] = True)");
            ScriptBuilder.InsertText("\tIf (No Result)");
            ScriptBuilder.InsertText("\t\tFinish");
            ScriptBuilder.InsertText("\tQueue.Enqueue(i)");
            ScriptBuilder.InsertText("\tFree[i] = False");
            ScriptBuilder.InsertText("\tWhile (Queue.Count > 0)");
            ScriptBuilder.InsertText("\t\tCurrent = Queue.Dequeue");
            ScriptBuilder.InsertText("\t\tFor Each (Vertex j in Adj(Current))");
            ScriptBuilder.InsertText("\t\t\tQueue.Enqueue(j)");
            ScriptBuilder.InsertText("\t\t\tFree[j] = False");
            ScriptBuilder.EndStep();
        }
    }
}
